package httpserver

import (
	"../files"
	"../luahelper"
	lua "github.com/yuin/gopher-lua"
	"io/ioutil"
	"log"
	"net/http"
	"path"
	"strings"
)

func RegisterFunc_4lua(l *lua.LState) {
	funcTable := l.SetFuncs(l.NewTable(), map[string]lua.LGFunction{
		"ListenAndServe": ListenAndServe_4lua,
	})

	l.SetGlobal("HttpServer", funcTable)
}

func ListenAndServe_4lua(l *lua.LState) int {
	// HttpServer.ListenAndServe(":80", "Web")

	host := l.ToString(1)
	path := l.ToString(2)

	go func() {
		//
		//r := mux.NewRouter()
		//r.HandleFunc("/", luaHttpServe(path))

		http.HandleFunc("/", luaHttpServe(path))

		log.Println("listen on", host, path)

		err := http.ListenAndServe(host, nil)
		if err != nil {
			log.Println(err)
		}
	}()

	return 0
}

func luaHttpServe(webPath string) func(http.ResponseWriter, *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if err, ok := recover().(error); ok {
				log.Println(err)
			}
		}()

		luafile := path.Join(webPath, r.URL.Path)

		log.Printf("do lua file %s\r\n", luafile)

		if files.Exists(luafile) != true {
			w.WriteHeader(404)
			w.Write([]byte("not found page."))

			println("not found file")
			return
		}

		if strings.HasSuffix(luafile, ".lua") == false {
			w.WriteHeader(404)
			w.Write([]byte("not found page."))

			log.Printf("files must be xxx.lua, but %s was not\r\n", luafile)
			return
		}

		l := lua.NewState()
		defer l.Close()

		luahelper.RegisterAllFunc(l)

		writer := getWriteTable(l, w)
		l.SetGlobal("Response", writer)

		reader := getRequestTable(l, r)
		l.SetGlobal("Request", reader)

		err := l.DoFile(luafile)
		if err != nil {
			log.Println(err)
		}
	}
}

func getWriteTable(l *lua.LState, w http.ResponseWriter) (t *lua.LTable) {
	t = l.NewTable()

	l.SetField(t, "WriteBody", l.NewFunction(func(l1 *lua.LState) int {
		body := l1.ToString(1)
		w.Write([]byte(body))
		return 0
	}))

	l.SetField(t, "WriteStatusCode", l.NewFunction(func(l1 *lua.LState) int {
		code := l1.ToInt(1)
		w.WriteHeader(code)
		return 0
	}))

	l.SetField(t, "AddHeader", l.NewFunction(func(l1 *lua.LState) int {
		key := l1.ToString(1)
		value := l1.ToString(2)
		w.Header().Add(key, value)
		return 0
	}))

	return
}

func getRequestTable(l *lua.LState, r *http.Request) (t *lua.LTable) {
	t = l.NewTable()

	l.SetField(t, "HttpMethod", lua.LString(r.Method))
	l.SetField(t, "Url", lua.LString(r.URL.Path))
	l.SetField(t, "QueryString", lua.LString(r.URL.RawQuery))
	query := l.NewTable()
	if r.URL.RawQuery != "" {
		items := strings.Split(r.URL.RawQuery, "&")
		for _, v := range items {
			i := strings.Index(v, "=")
			key := string([]rune(v)[:i])
			value := string([]rune(v)[i+1:])

			l.SetField(query, key, lua.LString(value))
		}
	}
	l.SetField(t, "Query", query)

	if r.Header != nil {
		headers := l.NewTable()
		for k, v := range r.Header {
			l.SetField(headers, k, lua.LString(strings.Join(v, ";")))
		}
		l.SetField(t, "Headers", headers)
	}

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Println(err.Error())
	} else {
		l.SetField(t, "Body", lua.LString(string(body)))
	}

	return
}
